package fr.lelouet.server.perf.snapshot;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.lelouet.tools.Configurable;

/**
 * an hypervisor snapshot receives informations on its virtualMachine's
 * snapshots.
 */
public class HVSnapshot extends ActivityReport implements Serializable,
		Configurable {

	private static final long serialVersionUID = 1L;

	private static final Logger logger = LoggerFactory
			.getLogger(HVSnapshot.class);

	/** that type means this is an hypervisor's activity's report. */
	public static final String HV_ACTIVITY_TYPE = "HV";

	public HVSnapshot() {
		setActivityType(HV_ACTIVITY_TYPE);
	}

	public HVSnapshot(HVSnapshot from) {
		this();
		entrySet().addAll(from.entrySet());
		vmSnapshots.entrySet().addAll(from.vmSnapshots.entrySet());
		vmage_ms = from.vmage_ms;
	}

	/**
	 * map of last vms' id to their last snapshot usages, that are handled by
	 * this hypervisor
	 */
	private Map<String, ActivityReport> vmSnapshots = new HashMap<String, ActivityReport>();

	/**
	 * the key to specify in configuration how many ms a VM should be kept in
	 * memory when no information has been received. ie, the timeout to set the
	 * vm to "destroyed"
	 */
	public static final String VMAGE_MS_KEY = "snapshot.vmage_ms";

	public static final Long VM_AGE_MS_DEFAULT = 60000L;

	/** the number of ms a VM is kept in memory while not being refreshed */
	protected long vmage_ms = VM_AGE_MS_DEFAULT;

	public void setVMMaxAge(long ms) {
		vmage_ms = ms;
	}

	@Override
	public void configure(Properties prop) {
		try {
			setVMMaxAge(Long.parseLong(prop.getProperty(VMAGE_MS_KEY,
					VM_AGE_MS_DEFAULT.toString())));
		} catch (Exception e) {
			logger.warn(e.toString());
		}
	}

	protected ActivityReport getReport(String name) {
		ActivityReport ru = vmSnapshots.get(name);
		if (ru == null) {
			ru = new ActivityReport();
			vmSnapshots.put(name, ru);
		}
		return ru;
	}

	public boolean updateVM(Map<String, String> values, long lastUpdate,
			long duration, String name) {
		return getReport(name).update(values, lastUpdate, duration);
	}

	public boolean updateVM(ActivityReport vm, String name) {
		return getReport(name).update(vm);
	}

	public Map<String, ActivityReport> getStoredVmsUsages() {
		return vmSnapshots;
	}

	public void removeOldVMs() {
		long minVMLastUpdate = getDate() - vmage_ms;
		List<String> idToRemove = new ArrayList<String>();
		for (Entry<String, ActivityReport> e : vmSnapshots.entrySet()) {
			if (e.getValue().getDate() < minVMLastUpdate) {
				idToRemove.add(e.getKey());
			}
		}
		logger.debug("removing vms snapshots for : {}",
				new Object[] { idToRemove });
		vmSnapshots.keySet().removeAll(idToRemove);
	}

	/**
	 * sums the events on each vms and put them as the host event.
	 * 
	 * @return a map of the sum of each events of the snapshot
	 */
	public Map<String, Double> unfold() {
		HashMap<String, Double> ret = new HashMap<String, Double>();
		for (ActivityReport vm : vmSnapshots.values()) {
			for (Entry<String, Float> e : vm.entrySet()) {
				String key = e.getKey();
				Double oldval = ret.get(key);
				ret.put(key, (oldval == null ? 0 : oldval) + e.getValue());
			}
		}
		return ret;
	}

}